package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.google.common.collect.Lists;
import com.zzyl.base.PageResponse;
import com.zzyl.dto.DeviceDto;
import com.zzyl.entity.Device;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.service.DeviceService;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.vo.DeviceVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class DeviceServiceImpl implements DeviceService {

    @Resource
    private Client client;

    @Resource
    private DeviceMapper deviceMapper;

    @Value("${zzyl.aliyun.iotInstanceId}")
    private String iotInstanceId;

    /**
     * 新增设备
     * @param deviceDto
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void registerDevice(DeviceDto deviceDto) throws Exception {
        // 1.IOT中新增设备
        RegisterDeviceRequest registerDeviceRequest = deviceDto.getRegisterDeviceRequest();
        registerDeviceRequest.setIotInstanceId(iotInstanceId);
        RegisterDeviceResponse registerDeviceResponse = client.registerDevice(registerDeviceRequest);
        // 2.判断是否新增成功
        if (!registerDeviceResponse.getBody().success) {
            throw new BaseException(registerDeviceResponse.getBody().errorMessage);
        }
        // 3.DB中新增设备
        Device device = BeanUtil.copyProperties(deviceDto, Device.class);
        device.setDeviceId(registerDeviceResponse.getBody().getData().getIotId());
        device.setProductId(deviceDto.getProductKey());
        device.setNoteName(deviceDto.getNickname());
        // 4.查询产品名称
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        queryProductRequest.setIotInstanceId(iotInstanceId)
                .setProductKey(deviceDto.getProductKey());
        QueryProductResponse queryProductResponse = client.queryProduct(queryProductRequest);
        if (queryProductResponse.getBody().success && ObjectUtil.isNotNull(queryProductResponse.getBody().getData())) {
            device.setProductName(queryProductResponse.getBody().getData().getProductName());

        }
        // 5.判断设备接入类别
        if (deviceDto.getLocationType() == 0) {
            device.setPhysicalLocationType(-1);
        }
        try {
            // 6.判断是否新增成功
            deviceMapper.insert(device);
        } catch (Exception e) {
            // DB新增失败，删除IOT设备
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotInstanceId(iotInstanceId);
            deleteDeviceRequest.setDeviceName(device.getDeviceName());
            deleteDeviceRequest.setIotId(device.getDeviceId());
            deleteDeviceRequest.setProductKey(device.getProductId());
            client.deleteDevice(deleteDeviceRequest);
            throw new BaseException("该老人/位置已绑定该产品，请重新选择");
        }
    }

    @Override
    public void updateDevice(DeviceDto deviceDto) throws Exception {
        // 更新IOT设备数据
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(iotInstanceId);
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo nicknameInfo = BeanUtil.toBean(deviceDto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
        request.setDeviceNicknameInfo(Lists.newArrayList(nicknameInfo));
        BatchUpdateDeviceNicknameResponse response = client.batchUpdateDeviceNickname(request);
        if (Boolean.TRUE.equals(response.getBody().getSuccess())) {
            // 更新数据库设备数据
            Device device = BeanUtil.toBean(deviceDto, Device.class);
            device.setProductId(deviceDto.getProductKey());
            device.setNoteName(deviceDto.getNickname());
            Device device1 = deviceMapper.selectByPrimaryKey(device.getId());
            if (ObjectUtil.isEmpty(device1)) {
                device.setDeviceId(deviceDto.getIotId());
                device.setNoteName(deviceDto.getNickname());
                device.setProductId(deviceDto.getProductKey());
                device.setDeviceId(deviceDto.getIotId());
                deviceMapper.insert(device);
                return;
            }
            try {
                deviceMapper.updateByPrimaryKeySelective(device);
            }catch (Exception e) {
                throw new BaseException("该老人/位置已绑定该产品，请重新选择");
            }
            return;
        }
        throw new BaseException(response.getBody().getErrorMessage());
    }

    @Override
    public PageResponse<DeviceVo> queryDevice(QueryDeviceRequest request) throws Exception {
        // 查询IOT设备列表
        QueryDeviceResponse response = client.queryDevice(request.setIotInstanceId(iotInstanceId));
        QueryDeviceResponseBody body = response.getBody();
        if (!body.success) {
            throw new BaseException(body.getErrorMessage());
        }
        if (ObjectUtil.isNull(body.data)) {
            return null;
        }
        List<QueryDeviceResponseBody.QueryDeviceResponseBodyDataDeviceInfo> deviceInfo = body.getData().getDeviceInfo();
        if (CollUtil.isEmpty(deviceInfo)) {
            return null;
        }
        // 取出所有设备ID
        Set<String> ids = deviceInfo.stream()
                .map(QueryDeviceResponseBody.QueryDeviceResponseBodyDataDeviceInfo::getIotId)
                .collect(Collectors.toSet());
        // 根据id集合批量查询设备
        List<DeviceVo> deviceVoList = deviceMapper.selectByDeviceIds(ids);
        if (CollUtil.isEmpty(deviceVoList)) {
            List<DeviceVo> deviceVos = BeanUtil.copyToList(deviceInfo, DeviceVo.class);
            return PageResponse.of(
                    deviceVos, body.getPage(), body.getPageSize(),
                    (long) body.getPageCount(), (long) body.getTotal()
            );
        }
        // 封装返回数据
        Map<String, DeviceVo> deviceMap = deviceVoList.stream()
                .collect(Collectors.toMap(DeviceVo::getDeviceId, Function.identity()));
        deviceVoList = deviceInfo.stream().map(item -> {
            DeviceVo deviceVo = deviceMap.get(item.getIotId());
            if (ObjectUtil.isNotNull(deviceVo)) {
                BeanUtil.copyProperties(item, deviceVo);
                return deviceVo;
            }
            return deviceVo;
        }).collect(Collectors.toList());
        return PageResponse.of(
                deviceVoList, body.getPage(), body.getPageSize(),
                (long) body.getPageCount(), (long) body.getTotal()
        );
    }

    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) throws Exception {
        // 查询IOT设备详情
        QueryDeviceDetailResponse response = client.queryDeviceDetail(request.setIotInstanceId(iotInstanceId));
        if (!response.getBody().success) {
            throw new BaseException(response.getBody().getErrorMessage());
        }
        QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData data = response.body.data;
        if (ObjectUtil.isNull(data)) {
            return null;
        }
        String iotId = data.getIotId();
        // 根据iotId查询设备
        List<DeviceVo> deviceVoList = deviceMapper.selectByDeviceIds(List.of(iotId));
        if (CollUtil.isEmpty(deviceVoList)) {
            return BeanUtil.copyProperties(data, DeviceVo.class);
        }
        deviceVoList.stream().findFirst().ifPresent(deviceVo -> {
            BeanUtil.copyProperties(data, deviceVo, CopyOptions.create().ignoreNullValue());
        });
        return deviceVoList.get(0);
    }

    @Override
    public void deleteDevice(DeleteDeviceRequest request) throws Exception {
        request.setIotInstanceId(iotInstanceId);
        DeleteDeviceResponse response = client.deleteDevice(request);
        if (Boolean.TRUE.equals(response.getBody().getSuccess())) {
            deviceMapper.deleteByDeviceId(request.getIotId());
            return;
        }
        throw new BaseException(response.getBody().getErrorMessage());
    }
}